10058. Поиск в
ширину 0 – 1 – 2
Задан неориентированный
граф. Вес его ребер может принимать только значения 0, 1 или 2. Найдите кратчайшее
расстояние между вершинами s и d.
Вход.
Первая строка содержит четыре целых числа: количество вершин n, количество ребер m (n, m ≤ 105) и номера вершин s и d (1 ≤ s, d ≤ n). Каждая из следующих m строк содержит три целых числа a, b и w задающих неориентированное ребро (a, b) весом w (0 ≤ w ≤ 2).
Выход.
Выведите кратчайший путь между вершинами s и d.
Пример входа |
Пример выхода |
5 5 1 4 1 2 1 2 3 0 3 4 2 1 5 2 4 5 2 |
3 |
поиск в
ширину
Для
каждого ребра (u, v)
весом 2 введем фиктивную вершину p и заменим его
двумя ребрами весом 1: (u, p) и (p,
v). Изначально
вершины нрафа пронумерованы числами 1, 2, …., n. Фиктивными будем
объявлять вершины n + 1, n + 2,
… . Поскольку ребер в графе существует не более m, то и
фиктивных вершин будет не более m.
Задача
сведена к использованию поиска в ширину на 0 – 1 графе.
Пример
Граф,
приведенный в примере, показан слева. Для каждого ребра весом 2 вводим
фиктивную вершину (вершины 6, 7, 8 - фиктивные). Справа приведен 0 – 1 граф.
Реализация алгоритма
Объявим константу бесконечность.
#define INF 0x3F3F3F3F
Объявим массив кратчайших расстояний dist и список
смежности графа g.
vector<int> dist;
vector<vector<pair<int, int> > > g;
Функция bfs реализует поиск в ширину на 0 – 1 графе из
вершины start.
void bfs(int start)
{
dist = vector<int>(n + 1, INF);
dist[start] = 0;
deque<int> q;
q.push_back(start);
while (!q.empty())
{
int v = q.front();
q.pop_front();
for (int i = 0; i < g[v].size(); i++)
{
int to = g[v][i].first;
int w = g[v][i].second;
if (dist[to] > dist[v] + w)
{
dist[to] = dist[v] + w;
if (w == 1)
q.push_back(to);
else
q.push_front(to);
}
}
}
}
Основная часть программы. Читаем входные данные. Строим
граф.
scanf("%d %d %d %d", &n, &m, &s, &d);
В результирующем графе с учетом фиктивных вершин будет не
более n
+ m.
g.resize(n + m + 1);
for (i = 0; i < m; i++)
{
scanf("%d %d
%d", &a, &b, &w);
if (w <= 1)
{
g[a].push_back(make_pair(b,
w));
g[b].push_back(make_pair(a,
w));
}
else
{
Обрабатываем ребро длины 2. Вводим фиктивную вершину,
увеличиваем количество вершин на 1.
n++;
Проводим неориентированные ребра (a,
n), (n, b) весом
1.
g[a].push_back(make_pair(n, 1));
g[n].push_back(make_pair(b, 1));
g[b].push_back(make_pair(n, 1));
g[n].push_back(make_pair(a, 1));
}
}
Запускаем поиск в ширину из стартовой вершины s.
bfs(s);
Выводим кратчайший путь до вершины d.
printf("%d\n", dist[d]);